package de.hsb.ai.util;

import jade.content.lang.Codec;
import jade.content.lang.sl.SLCodec;
import jade.content.onto.Ontology;
import jade.core.AID;
import jade.core.Agent;
import jade.domain.FIPANames;
import jade.domain.FIPAAgentManagement.ServiceDescription;
import jade.domain.JADEAgentManagement.JADEManagementOntology;
import jade.lang.acl.ACLMessage;
import jade.lang.acl.MessageTemplate;

import java.io.File;
import java.io.FileReader;
import java.io.IOException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import de.hsb.ai.domain.ScotlandJadeOntology;

/**
 * ScotlandyardHelper provides a set of utility-methods. 
 */
public class ScotlandJadeHelper {

	public static final String MSG_PROTOCOL = FIPANames.InteractionProtocol.FIPA_REQUEST;
	public static final String MSG_LANGUAGE = FIPANames.ContentLanguage.FIPA_SL;
	public static final Ontology MSG_ONTOLOGY = ScotlandJadeOntology.getInstance();
	public static final Codec MSG_CODEC = new SLCodec();
	
	public static final Logger logger = LoggerFactory.getLogger("sy.helper");
	
	public static final File APP_DIR;
	
	public static final ScotlandJadeConfig config = new ScotlandJadeConfig();
	
	static {
		File homeDir = new File(System.getProperty("user.home"));
		APP_DIR = new File(homeDir, ".scotland-jade");
		if (!APP_DIR.exists()) {
			if (!APP_DIR.mkdir()) {
				logger.error("failed to create " + APP_DIR);
			} else {
				logger.debug("created " + APP_DIR);
			}
		} else {
			logger.debug("app directory exists");
		}
		
		File configFile = new File(APP_DIR, "config.ini");
		try {
			configFile.createNewFile();
			config.load(new FileReader(configFile));
		} catch (IOException e) {
			logger.error("create config file", e);
		}		
	}

	private static final ScotlandJadeHelper instance = new ScotlandJadeHelper();

	public static ScotlandJadeHelper getInstance() {
		return instance;
	}
	
	public static ServiceDescription createServiceTemplate() {
		ServiceDescription sd = new ServiceDescription();
		sd.addOntologies(ScotlandJadeHelper.MSG_ONTOLOGY.getName());
		sd.addLanguages(ScotlandJadeHelper.MSG_LANGUAGE);
		return sd;
	}
	
	/**
	 * DevilHelper constructor
	 */
	private ScotlandJadeHelper() {

	}
	
	public static boolean hasToRevealAt(int move) {
		return (move - 3) % 5 == 0;
	}
	
	public static MessageTemplate createMessageTemplate(int...performatives) {
		MessageTemplate mt = createMessageTemplate();
		for (int performative : performatives) 
			mt = MessageTemplate.or(mt, MessageTemplate.MatchPerformative(performative));
		return mt;
	}
	
	public static MessageTemplate createMessageTemplate() {
		return MessageTemplate.and(
				MessageTemplate.MatchProtocol(MSG_PROTOCOL),
				MessageTemplate.and(
						MessageTemplate.MatchOntology(MSG_ONTOLOGY.getName()), 
						MessageTemplate.MatchLanguage(MSG_LANGUAGE)));
	}
	
	public static ACLMessage createAMSRequest(Agent sender) {
		Ontology ontology = JADEManagementOntology.getInstance();
		ACLMessage req = new ACLMessage(ACLMessage.REQUEST);
		req.addReceiver(sender.getAMS());
		req.setProtocol(MSG_PROTOCOL);
		req.setLanguage(FIPANames.ContentLanguage.FIPA_SL0);
		req.setOntology(ontology.getName());

		return req;
	}
	
	public static ACLMessage createDevilRequest(Agent sender, AID receiver, int type) {
		ACLMessage req = new ACLMessage(type);
		req.addReceiver(receiver);
		req.setProtocol(MSG_PROTOCOL);
		req.setLanguage(MSG_LANGUAGE);
		req.setOntology(MSG_ONTOLOGY.getName());
		
		return req;
	}
	
	/**
	 * Teaches specified agent's content-manager how to speak/understand devil.
	 * @param agent
	 */
	public static void learnDevil(Agent agent) {
		agent.getContentManager().registerLanguage(MSG_CODEC, MSG_LANGUAGE);
		agent.getContentManager().registerOntology(MSG_ONTOLOGY);
	}
	
	/**
	 * Teaches specified agent's content-manager how to speak/understand AMS
	 * @param agent
	 */
	public static void learnAMS(Agent agent) {
		agent.getContentManager().registerLanguage(MSG_CODEC, FIPANames.ContentLanguage.FIPA_SL0);
		agent.getContentManager().registerOntology(JADEManagementOntology.getInstance());
	}
	
	public static ScotlandJadeGameLogger createGameLogger() {
		return createGameLogger(0, null);
	}

	/**
	 * Creates a new game logger. If logging is not enabled it returns a mock-logger.
	 * @param detectives number of detectives involved
	 * @param fugitive name of the fugitive
	 * @see ScotlandJadeConfig#isGameLoggingEnabled()
	 * @return a new game logger
	 */
	public static ScotlandJadeGameLogger createGameLogger(int detectives, String fugitive) {
		File logDir = new File(ScotlandJadeHelper.APP_DIR, "log");
		if (!logDir.exists()) {
			if (logDir.mkdir()) {
				logger.debug("created log dir");
			} else {
				logger.error("failed to create log dir " + logDir);
			}
		}
		
		fugitive = fugitive == null || fugitive.isEmpty() ? "default" : fugitive.toLowerCase();
		
		StringBuilder logFileNameTemplate = new StringBuilder("game-")
		.append(detectives == 0 ? "\\d+" : detectives).append('-')
		.append(fugitive).append("-%03d.log");
		
		return new ScotlandJadeGameLogger(new File(logDir, logFileNameTemplate.toString()).getAbsolutePath(), config.isGameLoggingEnabled());
	}
	
}
